#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
Package JSON Generator
Scans plugins directory for r_info.py files and generates package.json files
"""

import json
import os
import sys
import ast
import argparse


def extract_field_expression(file_path, field_name, field_type):
    """
    Extract the raw expression from r_info.py file for a specific field
    
    Args:
        file_path (str): Path to r_info.py file
        field_name (str): Name of the field to extract
        field_type (str): Type of the field (e.g., 'str', 'bool', 'List[str]')
        
    Returns:
        str: Raw expression string for the field
    """
    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            content = f.read()
        
        # Look for the field assignment
        start_marker = f"{field_name}: {field_type} ="
        start_index = content.find(start_marker)
        
        if start_index == -1:
            return ""
        
        # Find the start of the expression (after the equals sign)
        expr_start = content.find('=', start_index) + 1
        
        # Handle different types of expressions
        if field_type.startswith('List['):
            # For list types, find the matching closing bracket
            bracket_count = 0
            expr_end = -1
            
            for i in range(expr_start, len(content)):
                if content[i] == '[':
                    bracket_count += 1
                elif content[i] == ']':
                    bracket_count -= 1
                    if bracket_count == 0:
                        expr_end = i + 1
                        break
            
            if expr_end == -1:
                # If no closing bracket found, find end of line
                expr_end = content.find('\n', expr_start)
                if expr_end == -1:
                    expr_end = len(content)
        else:
            # For simple types, find the end of the expression (next newline or end of file)
            expr_end = content.find('\n', expr_start)
            if expr_end == -1:
                expr_end = len(content)
        
        # Extract the expression and clean it up
        expression = content[expr_start:expr_end].strip()
        
        # If it's a string, remove the quotes
        if field_type == "str" and expression.startswith('"') and expression.endswith('"'):
            expression = expression[1:-1]
        elif field_type == "str" and expression.startswith("'") and expression.endswith("'"):
            expression = expression[1:-1]
        
        return expression
    except Exception as e:
        print(f"Warning: Could not extract {field_name} expression: {e}")
        return ""


def extract_dependencies_as_list(file_path):
    """
    Extract the Dependencies expression and convert it to a Python list
    
    Args:
        file_path (str): Path to r_info.py file
        
    Returns:
        list: Actual list of dependencies
    """
    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            content = f.read()
        
        # Look for the Dependencies assignment
        start_marker = "Dependencies: List[str] "
        start_index = content.find(start_marker)
        
        if start_index == -1:
            return []
        
        # Find the start of the expression (after the equals sign)
        expr_start = content.find('=', start_index) + 1
        
        # Find the matching closing bracket
        bracket_count = 0
        expr_end = -1
        
        for i in range(expr_start, len(content)):
            if content[i] == '[':
                bracket_count += 1
            elif content[i] == ']':
                bracket_count -= 1
                if bracket_count == 0:
                    expr_end = i + 1
                    break
        
        if expr_end == -1:
            return []
        
        # Extract the expression
        expression = content[expr_start:expr_end].strip()
        
        # Safely evaluate the expression as a Python list
        dependencies_list = ast.literal_eval(expression)
        return dependencies_list
    except Exception as e:
        print(f"Warning: Could not extract Dependencies as list: {e}")
        return []


def extract_supports_expression(file_path):
    """
    Extract the raw Supports expression from r_info.py file and format it as a list string
    
    Args:
        file_path (str): Path to r_info.py file
        
    Returns:
        str: Formatted string for Supports field with brackets
    """
    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            content = f.read()
        
        # Look for the Supports assignment
        start_marker = "Supports: List[int] = ["
        start_index = content.find(start_marker)
        
        if start_index == -1:
            return "[]"
        
        # Find the start of the expression (after the equals sign)
        expr_start = start_index + len("Supports: List[int] =")
        
        # Find the end of the expression (matching closing bracket)
        bracket_count = 0
        expr_end = -1
        
        for i in range(expr_start, len(content)):
            if content[i] == '[':
                bracket_count += 1
            elif content[i] == ']':
                bracket_count -= 1
                if bracket_count == 0:
                    expr_end = i + 1
                    break
        
        if expr_end == -1:
            return "[]"
        
        # Extract the expression
        expression = content[expr_start:expr_end].strip()
        
        # Remove extra whitespace while keeping brackets
        # Split by comma and clean up each part
        if expression.startswith('[') and expression.endswith(']'):
            # Extract content between brackets
            inner_content = expression[1:-1]
            parts = inner_content.split(',')
            cleaned_parts = []
            for part in parts:
                cleaned_part = part.strip()
                if cleaned_part:
                    cleaned_parts.append(cleaned_part)
            
            # Join with comma and space, and add brackets back
            return "[" + ", ".join(cleaned_parts) + "]"
        else:
            return expression
    except Exception as e:
        print(f"Warning: Could not extract Supports expression: {e}")
        return "[]"


def generate_package_json_from_r_info(r_info_path, output_path=None):
    """
    Generate package.json from RInfo class attributes
    
    Args:
        r_info_path (str): Path to r_info.py file
        output_path (str): Path where package.json should be created.
                          If None, creates in the same directory as r_info.py
    """
    # Add the directory containing r_info.py to the path so we can import it
    r_info_dir = os.path.dirname(r_info_path)
    sys.path.insert(0, r_info_dir)
    
    try:
        # Import the RInfo class dynamically
        import importlib.util
        spec = importlib.util.spec_from_file_location("r_info", r_info_path)
        r_info_module = importlib.util.module_from_spec(spec)
        spec.loader.exec_module(r_info_module)
        RInfo = r_info_module.RInfo
    except Exception as e:
        print(f"Error: Could not import RInfo from {r_info_path}: {e}")
        return False
    finally:
        # Remove the directory from path
        if r_info_dir in sys.path:
            sys.path.remove(r_info_dir)
    
    # Create an instance of RInfo to access its attributes
    r_info = RInfo()
    
    # Extract the raw Category expression
    category_expr = extract_field_expression(r_info_path, "Category", "str")
    
    # Extract the raw License expression
    license_expr = extract_field_expression(r_info_path, "License", "str")
    
    # Extract the Dependencies as an actual list
    dependencies_list = extract_dependencies_as_list(r_info_path)
    
    # Map RInfo attributes to package.json fields
    package_data = {
        "name": getattr(r_info, 'Name', 'unnamed-package'),
        "version": getattr(r_info, 'Version', '0.0.0'),
        "description": getattr(r_info, 'Description', ''),
        "vendor": getattr(r_info, 'Vendor', ''),
        "license": license_expr if license_expr else getattr(r_info, 'License', ''),
        "url": getattr(r_info, 'Url', ''),
        # Add other relevant fields as needed
        "compatVersion": getattr(r_info, 'CompatVersion', ''),
        "required": getattr(r_info, 'Required', False),
        "copyright": getattr(r_info, 'Copyright', ''),
        "category": category_expr if category_expr else getattr(r_info, 'Category', ''),
        "dependencies": dependencies_list if dependencies_list else getattr(r_info, 'Dependencies', []),
        "arguments": getattr(r_info, 'Arguments', []),
    }
    
    # Extract the raw Supports expression from the file
    supports_expr = extract_supports_expression(r_info_path)
    package_data["supports"] = supports_expr
    
    # Filter out empty values, but keep license even if empty
    filtered_data = {}
    for key, value in package_data.items():
        # Always include license field, even if empty
        if key == "license":
            filtered_data[key] = value
        elif value or isinstance(value, (int, float, bool)):  # Keep falsy numbers and booleans
            if isinstance(value, dict) and not value:  # Skip empty dicts
                continue
            if isinstance(value, list) and not value:  # Skip empty lists
                continue
            filtered_data[key] = value
    
    # Set default output path if not provided
    if output_path is None:
        output_path = os.path.join(r_info_dir, 'package.json')
    
    # Write package.json file
    try:
        with open(output_path, 'w', encoding='utf-8') as f:
            json.dump(filtered_data, f, indent=2, ensure_ascii=False)
        print(f"Successfully generated {output_path}")
        return True
    except Exception as e:
        print(f"Error writing package.json: {e}")
        return False


def scan_and_generate_plugins_json(plugins_dir):
    """
    Scan plugins directory for r_info.py files and generate package.json files
    
    Args:
        plugins_dir (str): Path to plugins directory
    """
    if not os.path.exists(plugins_dir):
        print(f"Error: Plugins directory {plugins_dir} does not exist")
        return False
    
    if not os.path.isdir(plugins_dir):
        print(f"Error: {plugins_dir} is not a directory")
        return False
    
    # Walk through the plugins directory
    generated_count = 0
    for root, dirs, files in os.walk(plugins_dir):
        # Check if current directory contains r_info.py
        if 'r_info.py' in files:
            r_info_path = os.path.join(root, 'r_info.py')
            print(f"Found r_info.py in {root}")
            
            # Generate package.json in the same directory
            success = generate_package_json_from_r_info(r_info_path)
            if success:
                generated_count += 1
    
    print(f"Generated {generated_count} package.json files")
    return generated_count > 0


def main():
    """Main function to generate package.json files"""
    parser = argparse.ArgumentParser(description='Generate package.json files from r_info.py files in plugins directory')
    parser.add_argument('plugins_dir', nargs='?', default='src/plugins', 
                       help='Path to plugins directory (default: src/plugins)')
    
    args = parser.parse_args()
    
    success = scan_and_generate_plugins_json(args.plugins_dir)
    sys.exit(0 if success else 1)


if __name__ == "__main__":
    main()